package com.owen.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import com.owen.emuns.PdfTypeEnums;
import com.owen.service.AppService;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.multipdf.PDFCloneUtility;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.NumberToTextConverter;

import java.awt.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

public class AppServiceImpl implements AppService {


    /**
     * 仅支持Windows系统
     * 打开某自定目录
     *
     * @param folder
     */
    private void openWinDirectory(File folder) {
        // 获取系统名
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().contains("win") && folder.exists() && folder.isDirectory()) {
            try {
                Desktop.getDesktop().open(folder);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("Folder does not exist.");
        }
    }

    @Override
    public String splitPageOneMergePDF(List<Path> pdfPaths, String pathStr, PdfTypeEnums pdfTypeEnum) throws IOException {
        // 将要被导出的pdf
        PDDocument outputDoc = new PDDocument();
        List<PDDocument> inputPdfDocuments = new ArrayList<>();
        // 遍历该文件夹下的所有一级文件
        for (Path pdfPath : pdfPaths) {
            try {
                // 加载Pdf
                PDDocument document = PDDocument.load(pdfPath.toFile());
                if (document != null) {
                    inputPdfDocuments.add(document);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        for (PDDocument document : inputPdfDocuments) {
            // 取出该Pdf的第一页
            PDPage page = document.getPage(0);
            PDRectangle pdRectangle = pdfTypeEnum.getPdRectangle();
            page.setMediaBox(pdRectangle);
            // 添加至要导出的pdf对象中
            outputDoc.addPage(page);
        }

        // 生成PDF文件名
        String outPdfFileName = UUID.randomUUID().toString().concat(".pdf");
        // 组合Pdf保存路径

        String outputFilePath = pathStr.concat(File.separator).concat("export").concat(File.separator);
        File outFile = new File(outputFilePath);
        if (!outFile.exists())
            outFile.mkdirs();
        String outPdfFilePath = outputFilePath.concat(outPdfFileName);
        outputDoc.save(outPdfFilePath);
        outputDoc.close();

        for (PDDocument document : inputPdfDocuments) {
            document.close();
        }

        return outPdfFilePath;
    }

    @Override
    public List<String> readExcelByHead(String excelPath, String head) {
        Path path = Paths.get(excelPath);
        if (!Files.exists(path)) {
            throw new RuntimeException(String.format("[%s] 文件不存在", excelPath));
        }
        List<String> contents = new ArrayList<>();

        InputStream inputStream = null;
        Workbook workbook = null;
        try {
            inputStream = Files.newInputStream(path);
            workbook = WorkbookFactory.create(inputStream);
            // 获取第一个sheet
            Sheet sheet0 = workbook.getSheetAt(0);
            // 读取第一行
            Row rowHead = sheet0.getRow(0);
            // 总行数
            int physicalNumberOfRows = sheet0.getPhysicalNumberOfRows();
            // 获取列数
            int physicalNumberOfCells = rowHead.getPhysicalNumberOfCells();
            // 存储表头数据
            List<String> headContents = new ArrayList<>();

            for (int i = 0; i < physicalNumberOfCells; i++) {
                Cell cell = rowHead.getCell(i);
                headContents.add(cell.getStringCellValue());
            }
            int headIndex = headContents.indexOf(head);
            if (headIndex == -1) {
                throw new RuntimeException(String.format("未找到[%s]列", head));
            }
            // 读取该列数据
            for (int i = 1; i < physicalNumberOfRows; i++) {
                Cell cell = sheet0.getRow(i).getCell(headIndex);
                String content = cell.getStringCellValue();
                if (content != null && !content.isEmpty()) {
                    contents.add(content.trim());
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
                if (workbook != null) {
                    workbook.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }

        return contents;
    }


    @Override
    public void qrcodePdf(List<Path> pdfPaths, String pathStr) {
        TimeInterval timer = DateUtil.timer();
        for (Path pdfPath : pdfPaths) {
            // 将要被导出的pdf
            PDDocument outputDoc = new PDDocument();
            // 遍历该文件夹下的所有一级文件
            PDDocument document = null;
            try {
                // 加载Pdf
                document = PDDocument.load(pdfPath.toFile());
                // 遍历pdf的每一页
                for (int i = 0; i < document.getNumberOfPages(); i++) {
                    // 利用PDFCloneUtility获取document的每一页，避免直接应用导致pdf下一次接触产生误差
                    PDFCloneUtility cloneUtility01 = new PDFCloneUtility(document);
                    COSDictionary pageContent01 = (COSDictionary) cloneUtility01.cloneForNewDocument(document.getPage(i).getCOSObject());
                    PDPage page01 = new PDPage(pageContent01);

                    PDRectangle pdRectangle01 = new PDRectangle(150f, 490f, 300f, 300f);
                    // page01.setCropBox(pdRectangle01);
                    page01.setMediaBox(pdRectangle01);
                    outputDoc.addPage(page01);

                    PDFCloneUtility cloneUtility02 = new PDFCloneUtility(document);
                    COSDictionary pageContent02 = (COSDictionary) cloneUtility02.cloneForNewDocument(document.getPage(i).getCOSObject());
                    PDPage page02 = new PDPage(pageContent02);

                    PDRectangle pdRectangle02 = new PDRectangle(150f, 150f, 300f, 300f);
                    // page02.setCropBox(pdRectangle02);
                    page02.setMediaBox(pdRectangle02);
                    outputDoc.addPage(page02);

                }


            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                // 生成PDF文件名
                String outPdfFileName = pdfPath.getFileName().toString();
                // 组合Pdf保存路径
                String outputFilePath = pathStr.concat(File.separator).concat("export").concat(File.separator);
                File outFile = new File(outputFilePath);
                if (!outFile.exists())
                    outFile.mkdirs();
                String outPdfFilePath = outputFilePath.concat(outPdfFileName);
                try {
                    // 依次关闭各IO资源
                    outputDoc.save(outPdfFilePath);
                    outputDoc.close();
                    document.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.out.println(String.format("文件：%s生成完成，请查看。", outPdfFilePath));
            }
        }
        //花费毫秒数
        long interval = timer.interval();
        System.out.println(String.format("共耗时%d毫秒。", interval));
    }


    @Override
    public void oneCuttingThreePdf(List<Path> pdfPaths, String pathStr) {
        // 导入pdf目录
        String outputFilePath = pathStr.concat(File.separator).concat("export").concat(File.separator);
        File outFile = new File(outputFilePath);

        TimeInterval timer = DateUtil.timer();
        // 合并的最大PDF
        PDDocument allDoc = new PDDocument();

        for (Path pdfPath : pdfPaths) {
            // 将要被导出的pdf
            PDDocument outputDoc = new PDDocument();
            // 遍历该文件夹下的所有一级文件
            PDDocument document = null;
            try {
                // 加载Pdf
                document = PDDocument.load(pdfPath.toFile());
                // 遍历pdf的每一页
                for (int i = 0; i < document.getNumberOfPages(); i++) {
                    // 利用PDFCloneUtility获取document的每一页，避免直接应用导致pdf下一次接触产生误差
                    PDFCloneUtility cloneUtility01 = new PDFCloneUtility(document);
                    COSDictionary pageContent01 = (COSDictionary) cloneUtility01.cloneForNewDocument(document.getPage(i).getCOSObject());
                    PDPage page01 = new PDPage(pageContent01);
                    // 可利用此工具，方便的获取坐标
                    // https://blog.csdn.net/zzzgd_666/article/details/125277714 https://pdfbox.apache.org/download.cgi 坐标
                    PDRectangle pdRectangle01 = new PDRectangle(27f, 138f, 260f, 430f);
                    page01.setMediaBox(pdRectangle01);
                    outputDoc.addPage(page01);

                    PDFCloneUtility cloneUtility02 = new PDFCloneUtility(document);
                    COSDictionary pageContent02 = (COSDictionary) cloneUtility02.cloneForNewDocument(document.getPage(i).getCOSObject());
                    PDPage page02 = new PDPage(pageContent02);
                    PDRectangle pdRectangle02 = new PDRectangle(292, 138, 260f, 430f);
                    page02.setMediaBox(pdRectangle02);
                    outputDoc.addPage(page02);

                    PDFCloneUtility cloneUtility03 = new PDFCloneUtility(document);
                    COSDictionary pageContent03 = (COSDictionary) cloneUtility03.cloneForNewDocument(document.getPage(i).getCOSObject());
                    PDPage page03 = new PDPage(pageContent03);
                    PDRectangle pdRectangle03 = new PDRectangle(557, 138, 260f, 430f);
                    page03.setMediaBox(pdRectangle03);
                    outputDoc.addPage(page03);

                    // 将以下三页添加到最大的pdf合并文档中
                    // 将本页添加到最大的合并pdf文档中

                    PDFCloneUtility cloneUtilityAll = new PDFCloneUtility(allDoc);
                    COSDictionary pageContentAll01 = (COSDictionary) cloneUtilityAll.cloneForNewDocument(page01);
                    PDPage pageAll01 = new PDPage(pageContentAll01);
                    allDoc.addPage(pageAll01);
                    // 将本页添加到最大的合并pdf文档中
                    COSDictionary pageContentAll02 = (COSDictionary) cloneUtilityAll.cloneForNewDocument(page02);
                    PDPage pageAll02 = new PDPage(pageContentAll02);
                    allDoc.addPage(pageAll02);
                    // 将本页添加到最大的合并pdf文档中
                    COSDictionary pageContentAll03 = (COSDictionary) cloneUtilityAll.cloneForNewDocument(page03);
                    PDPage pageAll03 = new PDPage(pageContentAll03);
                    allDoc.addPage(pageAll03);
                }

            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                // 生成PDF文件名
                String outPdfFileName = pdfPath.getFileName().toString();
                // 组合Pdf保存路径
                if (!outFile.exists())
                    outFile.mkdirs();
                String outPdfFilePath = outputFilePath.concat(outPdfFileName);
                try {
                    // 依次关闭各IO资源
                    outputDoc.save(outPdfFilePath);
                    outputDoc.close();
                    document.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.out.println(String.format("文件：%s生成完成，请查看。", outPdfFilePath));
            }
        }


        // 生成所有pdf合并的pdf
        String allPdfFileName = UUID.randomUUID().toString().concat(".pdf");
        // 组合Pdf保存路径
        String allFilePath = pathStr.concat(File.separator).concat("export").concat(File.separator).concat("all").concat(File.separator);
        File allFile = new File(allFilePath);
        if (!allFile.exists())
            allFile.mkdirs();
        String allPdfFilePath = allFilePath.concat(allPdfFileName);
        try {
            // 依次关闭各IO资源
            allDoc.save(allPdfFilePath);
            allDoc.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 打开生成后文件目录
        openWinDirectory(outFile);
        // 打开生成合并pdf文件目录
        openWinDirectory(allFile);

        System.out.println(String.format("处理合并完成的pdf：%s生成完成，请查看。", allPdfFilePath));
        //花费毫秒数
        long interval = timer.interval();
        System.out.println(String.format("共耗时%d毫秒。", interval));
    }


    @Override
    public void excelColorSpain(String excelPath) {
        Path path = Paths.get(excelPath);
        if (!Files.exists(path)) {
            throw new RuntimeException(String.format("[%s] 文件不存在", excelPath));
        }

        // 用于存放所有中文表示的Key
        List<String> cnKeys = new ArrayList<>();
        // 中文和西班牙文的词典
        Properties cnSpain = new Properties();
        InputStream cnSpainPropertiesIs = null;
        InputStreamReader isr = null;
        try {
            // 初始化西班牙语词典
            cnSpainPropertiesIs = this.getClass().getClassLoader().getResourceAsStream("CN_Spain.properties");
            // 避免乱码
            isr = new InputStreamReader(cnSpainPropertiesIs, StandardCharsets.UTF_8);
            cnSpain.load(isr);
            // 将词典种的中文key值加入到cnKey中
            cnSpain.forEach((k, v) -> {
                cnKeys.add(String.valueOf(k));
            });
            // cnKey需按字数从大到小排序
            cnKeys.sort((k0, k1) -> Integer.valueOf(k1.length()).compareTo(Integer.valueOf(k0.length())));
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            // 关闭流，释放资源，避免电脑卡顿
            try {
                if (isr != null) {
                    isr.close();
                }
                if (cnSpainPropertiesIs != null) {
                    cnSpainPropertiesIs.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        InputStream inputStream = null;
        Workbook workbook = null;
        try {
            inputStream = Files.newInputStream(path);
            workbook = WorkbookFactory.create(inputStream);
            // 获取第一个sheet
            Sheet sheet0 = workbook.getSheetAt(0);
            // 读取第一行
            Row rowHead = sheet0.getRow(0);
            // 总行数
            int physicalNumberOfRows = sheet0.getPhysicalNumberOfRows();
            // 获取列数
            int physicalNumberOfCells = rowHead.getPhysicalNumberOfCells();

            // 遍历行列以扫描
            for (int r = 0; r < physicalNumberOfRows; r++) {
                Row row = sheet0.getRow(r);
                for (int c = 0; c < physicalNumberOfCells; c++) {
                    if (row == null)
                        continue;
                    String value = "";
                    Cell cell = row.getCell(c);
                    switch (cell.getCellType()) {
                        case STRING:
                            value = cell.getStringCellValue();
                            break;
                        case NUMERIC:
                            // 避免电话号码类型的数据是number类型导致读取出错
                            value = NumberToTextConverter.toText(cell.getNumericCellValue());
                            break;
                    }
                    boolean dictionaryMatch = false;
                    String key = "";
                    // 是否存在词典匹配值
                    for (String cnKey : cnKeys) {
                        if (value.contains(cnKey)) {
                            dictionaryMatch = true;
                            key = cnKey;
                            break;
                        }
                    }
                    // 在匹配值之后添加“（翻译值）”
                    if (dictionaryMatch) {
                        value = value.replace(key, String.format("（%s）%s", cnSpain.getProperty(key), key));
                        // 设置翻译值
                        cell.setCellValue(value);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 保存Excel文件
                // 获取Excel文件名
                String outExcelFileName = path.getFileName().toString();
                String outputFilePath = path.getParent().toString().concat(File.separator).concat("export").concat(File.separator);
                File outFile = new File(outputFilePath);
                // 组合Pdf保存路径
                if (!outFile.exists())
                    outFile.mkdirs();
                // 将要生成新文件的全路径
                String outExcelFilePath = outputFilePath.concat(outExcelFileName);
                OutputStream excelOs = Files.newOutputStream(Paths.get(outExcelFilePath));
                workbook.write(excelOs);
                // 打开生成文件所在目录
                openWinDirectory(outFile);
                System.out.println(String.format("处理完成：处理后的文件处于：%s", outExcelFilePath));
                if (workbook != null) {
                    workbook.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
                if (excelOs != null) {
                    excelOs.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }
    }


}
